#include "core_searchTree.h"
#include "mem_manager.h"

CSearchTree::TTreeItem *CSearchTree::createNode(TTreeItem *parent)
{
	TTreeItem *item;
	g_alloc(item, TTreeItem);

	item->parent = parent;
	for (int i=0;i<SEARCHTREE_MAXSPAN;i++)
		item->items[i] = NULL;

	item->data = NULL;
	return item;
}

int CSearchTree::getCharPos(char c)
{
	if ((c>='A')&&(c<='Z'))
		return c-'A';

	if ((c>='a')&&(c<='z'))
		return c-'a';

	if ((c>='0')&&(c<='9'))
		return (c-'0')+26;

	switch (c)
	{
	case '_':
		return 36;
	case '-':
		return 37;
	case '+':
		return 38;
	default:
		return 39;
	}
}

void CSearchTree::deleteChildren(TTreeItem *item)
{
	for (int i=0;i<SEARCHTREE_MAXSPAN;i++)
		if (item->items[i])
		{
			deleteChildren(item->items[i]);
			g_free(item->items[i]);
		}

	deleteData(item);
}

void CSearchTree::deleteData(TTreeItem *item)
{
	if (item->data)
	{
		if (item->data)
		{
			if (m_delCallback)
				m_delCallback(item->data);
			else
				g_free(item->data);
			item->data = NULL;
		}
	}
}

CSearchTree::CSearchTree()
{
	m_root = createNode(NULL);
	m_delCallback = NULL;
}

CSearchTree::~CSearchTree()
{
	deleteChildren(m_root);
	deleteData(m_root);
	g_free(m_root);
}

int CSearchTree::addNode(const char *name, void* data)
{
	int result = SEARCHTREE_NODEADDED;
	TTreeItem *item = m_root;
	int pos = 0;

	while (name[pos])
	{
		int c = getCharPos(name[pos]);
		
		if (item->items[c] == NULL)
		{
			item->items[c] = createNode(item);
			item->items[c]->c = name[pos];
		}

		pos++;
		item = item->items[c];
	}

	if (item->data)
		result = SEARCHTREE_NODEREPLACED;

	deleteData(item);
	item->data = data;

	return result;
}

void* CSearchTree::getNode(const char *name)
{
	TTreeItem *item = m_root;
	int pos = 0;

	while (name[pos])
	{
		int c = getCharPos(name[pos]);
		
		if (item->items[c] == NULL)
			return NULL;

		pos++;
		item = item->items[c];
	}

	return item->data;
}

int CSearchTree::deleteNode(const char *name)
{
	TTreeItem *item = m_root;
	int pos = 0;

	while (name[pos])
	{
		int c = getCharPos(name[pos]);
		
		if (item->items[c] == NULL)
			return SEARCHTREE_NODENOTFOUND;

		pos++;
		item = item->items[c];

	}

	deleteData(item);

	while (item != m_root)
	{
		int count = 0;
		for (int i=0;((i<SEARCHTREE_MAXSPAN)&&(count==0));i++)
			if (item->items[i])
				count++;

		if (count==0)
		{
			TTreeItem *tmp = item;
			item = item->parent;
			
			for (int i=0;i<SEARCHTREE_MAXSPAN;i++)
				if (item->items[i] == tmp)
				{
					g_free(item->items[i]);
					break;
				}
		}
		else
			return SEARCHTREE_NODEDELETED;
	}

	return SEARCHTREE_NODEDELETED;
}

TSearchTreeCallbackDelete CSearchTree::registerDeleteCallback(TSearchTreeCallbackDelete delCallback)
{
	TSearchTreeCallbackDelete old = m_delCallback;
	m_delCallback = delCallback;

	return old;
}
